mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Auto merge of #2696 - RalfJung:no-std-windows, r=RalfJung
make no_std work on Windows Also fixes https://github.com/rust-lang/miri/issues/1123 by cherry-picking a patch by `@DrMeepster.`
This commit is contained in:
commit
144b4859ad
@ -88,7 +88,6 @@ function run_tests_minimal {
|
|||||||
./miri test -- "$@"
|
./miri test -- "$@"
|
||||||
|
|
||||||
# Ensure that a small smoke test of cargo-miri works.
|
# Ensure that a small smoke test of cargo-miri works.
|
||||||
# Note: This doesn't work on windows because of TLS.
|
|
||||||
cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml
|
cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml
|
||||||
|
|
||||||
endgroup
|
endgroup
|
||||||
|
@ -9,6 +9,7 @@ use std::thread;
|
|||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
use rustc_hir::def::Namespace;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self,
|
self,
|
||||||
@ -195,7 +196,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
|||||||
MiriMachine::late_init(&mut ecx, config)?;
|
MiriMachine::late_init(&mut ecx, config)?;
|
||||||
|
|
||||||
// Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
|
// Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
|
||||||
let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"]);
|
let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"], Namespace::ValueNS);
|
||||||
if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) {
|
if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) {
|
||||||
tcx.sess.fatal(
|
tcx.sess.fatal(
|
||||||
"the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \
|
"the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \
|
||||||
|
@ -2,12 +2,12 @@ pub mod convert;
|
|||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::mem;
|
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
|
use rustc_hir::def::{DefKind, Namespace};
|
||||||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
@ -74,40 +74,71 @@ const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Gets an instance for a path.
|
/// Gets an instance for a path.
|
||||||
fn try_resolve_did<'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option<DefId> {
|
///
|
||||||
tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then(
|
/// A `None` namespace indicates we are looking for a module.
|
||||||
|krate| {
|
fn try_resolve_did<'tcx>(
|
||||||
let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX };
|
tcx: TyCtxt<'tcx>,
|
||||||
let mut items = tcx.module_children(krate);
|
path: &[&str],
|
||||||
let mut path_it = path.iter().skip(1).peekable();
|
namespace: Option<Namespace>,
|
||||||
|
) -> Option<DefId> {
|
||||||
|
/// Yield all children of the given item, that have the given name.
|
||||||
|
fn find_children<'tcx: 'a, 'a>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
item: DefId,
|
||||||
|
name: &'a str,
|
||||||
|
) -> impl Iterator<Item = DefId> + 'a {
|
||||||
|
tcx.module_children(item)
|
||||||
|
.iter()
|
||||||
|
.filter(move |item| item.ident.name.as_str() == name)
|
||||||
|
.map(move |item| item.res.def_id())
|
||||||
|
}
|
||||||
|
|
||||||
while let Some(segment) = path_it.next() {
|
// Take apart the path: leading crate, a sequence of modules, and potentially a final item.
|
||||||
for item in mem::take(&mut items).iter() {
|
let (&crate_name, path) = path.split_first().expect("paths must have at least one segment");
|
||||||
if item.ident.name.as_str() == *segment {
|
let (modules, item) = if let Some(namespace) = namespace {
|
||||||
if path_it.peek().is_none() {
|
let (&item_name, modules) =
|
||||||
return Some(item.res.def_id());
|
path.split_last().expect("non-module paths must have at least 2 segments");
|
||||||
}
|
(modules, Some((item_name, namespace)))
|
||||||
|
} else {
|
||||||
|
(path, None)
|
||||||
|
};
|
||||||
|
|
||||||
items = tcx.module_children(item.res.def_id());
|
// First find the crate.
|
||||||
break;
|
let krate =
|
||||||
}
|
tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == crate_name)?;
|
||||||
}
|
let mut cur_item = DefId { krate: *krate, index: CRATE_DEF_INDEX };
|
||||||
}
|
// Then go over the modules.
|
||||||
None
|
for &segment in modules {
|
||||||
},
|
cur_item = find_children(tcx, cur_item, segment)
|
||||||
)
|
.find(|item| tcx.def_kind(item) == DefKind::Mod)?;
|
||||||
|
}
|
||||||
|
// Finally, look up the desired item in this module, if any.
|
||||||
|
match item {
|
||||||
|
Some((item_name, namespace)) =>
|
||||||
|
Some(
|
||||||
|
find_children(tcx, cur_item, item_name)
|
||||||
|
.find(|item| tcx.def_kind(item).ns() == Some(namespace))?,
|
||||||
|
),
|
||||||
|
None => Some(cur_item),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
|
/// Checks if the given crate/module exists.
|
||||||
|
fn have_module(&self, path: &[&str]) -> bool {
|
||||||
|
try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets an instance for a path; fails gracefully if the path does not exist.
|
/// Gets an instance for a path; fails gracefully if the path does not exist.
|
||||||
fn try_resolve_path(&self, path: &[&str]) -> Option<ty::Instance<'tcx>> {
|
fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option<ty::Instance<'tcx>> {
|
||||||
let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path)?;
|
let tcx = self.eval_context_ref().tcx.tcx;
|
||||||
Some(ty::Instance::mono(self.eval_context_ref().tcx.tcx, did))
|
let did = try_resolve_did(tcx, path, Some(namespace))?;
|
||||||
|
Some(ty::Instance::mono(tcx, did))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an instance for a path.
|
/// Gets an instance for a path.
|
||||||
fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> {
|
fn resolve_path(&self, path: &[&str], namespace: Namespace) -> ty::Instance<'tcx> {
|
||||||
self.try_resolve_path(path)
|
self.try_resolve_path(path, namespace)
|
||||||
.unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
|
.unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
/// if the path could be resolved, and None otherwise
|
/// if the path could be resolved, and None otherwise
|
||||||
fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar<Provenance>> {
|
fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||||
let this = self.eval_context_ref();
|
let this = self.eval_context_ref();
|
||||||
let instance = this.resolve_path(path);
|
let instance = this.resolve_path(path, Namespace::ValueNS);
|
||||||
let cid = GlobalId { instance, promoted: None };
|
let cid = GlobalId { instance, promoted: None };
|
||||||
// We don't give a span -- this isn't actually used directly by the program anyway.
|
// We don't give a span -- this isn't actually used directly by the program anyway.
|
||||||
let const_val = this.eval_global(cid, None)?;
|
let const_val = this.eval_global(cid, None)?;
|
||||||
@ -147,7 +178,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
/// Helper function to get the `TyAndLayout` of a `libc` type
|
/// Helper function to get the `TyAndLayout` of a `libc` type
|
||||||
fn libc_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
|
fn libc_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
|
||||||
let this = self.eval_context_ref();
|
let this = self.eval_context_ref();
|
||||||
let ty = this.resolve_path(&["libc", name]).ty(*this.tcx, ty::ParamEnv::reveal_all());
|
let ty = this
|
||||||
|
.resolve_path(&["libc", name], Namespace::TypeNS)
|
||||||
|
.ty(*this.tcx, ty::ParamEnv::reveal_all());
|
||||||
this.layout_of(ty)
|
this.layout_of(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
fn windows_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
|
fn windows_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
|
||||||
let this = self.eval_context_ref();
|
let this = self.eval_context_ref();
|
||||||
let ty = this
|
let ty = this
|
||||||
.resolve_path(&["std", "sys", "windows", "c", name])
|
.resolve_path(&["std", "sys", "windows", "c", name], Namespace::TypeNS)
|
||||||
.ty(*this.tcx, ty::ParamEnv::reveal_all());
|
.ty(*this.tcx, ty::ParamEnv::reveal_all());
|
||||||
this.layout_of(ty)
|
this.layout_of(ty)
|
||||||
}
|
}
|
||||||
|
@ -261,6 +261,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
// (that would be basically https://github.com/rust-lang/miri/issues/450),
|
// (that would be basically https://github.com/rust-lang/miri/issues/450),
|
||||||
// we specifically look up the static in libstd that we know is placed
|
// we specifically look up the static in libstd that we know is placed
|
||||||
// in that section.
|
// in that section.
|
||||||
|
if !this.have_module(&["std"]) {
|
||||||
|
// Looks like we are running in a `no_std` crate.
|
||||||
|
// That also means no TLS dtors callback to call.
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
let thread_callback =
|
let thread_callback =
|
||||||
this.eval_windows("thread_local_key", "p_thread_callback")?.to_pointer(this)?;
|
this.eval_windows("thread_local_key", "p_thread_callback")?.to_pointer(this)?;
|
||||||
let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?;
|
let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?;
|
||||||
|
@ -11,7 +11,6 @@ use std::time::SystemTime;
|
|||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_middle::ty::{self, layout::LayoutOf};
|
|
||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::{Align, Size};
|
||||||
|
|
||||||
use crate::shims::os_str::bytes_to_os_str;
|
use crate::shims::os_str::bytes_to_os_str;
|
||||||
@ -1006,12 +1005,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
// as `isize`s instead of having the proper types. Thus, we have to recover the layout of
|
// as `isize`s instead of having the proper types. Thus, we have to recover the layout of
|
||||||
// `statxbuf_op` by using the `libc::statx` struct type.
|
// `statxbuf_op` by using the `libc::statx` struct type.
|
||||||
let statxbuf = {
|
let statxbuf = {
|
||||||
// FIXME: This long path is required because `libc::statx` is an struct and also a
|
let statx_layout = this.libc_ty_layout("statx")?;
|
||||||
// function and `resolve_path` is returning the latter.
|
|
||||||
let statx_ty = this
|
|
||||||
.resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"])
|
|
||||||
.ty(*this.tcx, ty::ParamEnv::reveal_all());
|
|
||||||
let statx_layout = this.layout_of(statx_ty)?;
|
|
||||||
MPlaceTy::from_aligned_ptr(statxbuf_ptr, statx_layout)
|
MPlaceTy::from_aligned_ptr(statxbuf_ptr, statx_layout)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
#![feature(lang_items, start)]
|
#![feature(lang_items, start)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
// windows tls dtors go through libstd right now, thus this test
|
|
||||||
// cannot pass. When windows tls dtors go through the special magic
|
|
||||||
// windows linker section, we can run this test on windows again.
|
|
||||||
//@ignore-target-windows: no-std not supported on Windows
|
|
||||||
|
|
||||||
// Plumbing to let us use `writeln!` to host stdout:
|
// Plumbing to let us use `writeln!` to host stdout:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user