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 -- "$@"
|
||||
|
||||
# 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
|
||||
|
||||
endgroup
|
||||
|
@ -9,6 +9,7 @@ use std::thread;
|
||||
use log::info;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::{
|
||||
self,
|
||||
@ -195,7 +196,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
||||
MiriMachine::late_init(&mut ecx, config)?;
|
||||
|
||||
// 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())) {
|
||||
tcx.sess.fatal(
|
||||
"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::iter;
|
||||
use std::mem;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::time::Duration;
|
||||
|
||||
use log::trace;
|
||||
|
||||
use rustc_hir::def::{DefKind, Namespace};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::{
|
||||
@ -74,40 +74,71 @@ const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
|
||||
};
|
||||
|
||||
/// 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(
|
||||
|krate| {
|
||||
let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX };
|
||||
let mut items = tcx.module_children(krate);
|
||||
let mut path_it = path.iter().skip(1).peekable();
|
||||
|
||||
while let Some(segment) = path_it.next() {
|
||||
for item in mem::take(&mut items).iter() {
|
||||
if item.ident.name.as_str() == *segment {
|
||||
if path_it.peek().is_none() {
|
||||
return Some(item.res.def_id());
|
||||
///
|
||||
/// A `None` namespace indicates we are looking for a module.
|
||||
fn try_resolve_did<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
path: &[&str],
|
||||
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())
|
||||
}
|
||||
|
||||
items = tcx.module_children(item.res.def_id());
|
||||
break;
|
||||
// Take apart the path: leading crate, a sequence of modules, and potentially a final item.
|
||||
let (&crate_name, path) = path.split_first().expect("paths must have at least one segment");
|
||||
let (modules, item) = if let Some(namespace) = namespace {
|
||||
let (&item_name, modules) =
|
||||
path.split_last().expect("non-module paths must have at least 2 segments");
|
||||
(modules, Some((item_name, namespace)))
|
||||
} else {
|
||||
(path, None)
|
||||
};
|
||||
|
||||
// First find the crate.
|
||||
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.
|
||||
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),
|
||||
}
|
||||
}
|
||||
None
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
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.
|
||||
fn try_resolve_path(&self, path: &[&str]) -> Option<ty::Instance<'tcx>> {
|
||||
let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path)?;
|
||||
Some(ty::Instance::mono(self.eval_context_ref().tcx.tcx, did))
|
||||
fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option<ty::Instance<'tcx>> {
|
||||
let tcx = self.eval_context_ref().tcx.tcx;
|
||||
let did = try_resolve_did(tcx, path, Some(namespace))?;
|
||||
Some(ty::Instance::mono(tcx, did))
|
||||
}
|
||||
|
||||
/// Gets an instance for a path.
|
||||
fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> {
|
||||
self.try_resolve_path(path)
|
||||
fn resolve_path(&self, path: &[&str], namespace: Namespace) -> ty::Instance<'tcx> {
|
||||
self.try_resolve_path(path, namespace)
|
||||
.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
|
||||
fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
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 };
|
||||
// We don't give a span -- this isn't actually used directly by the program anyway.
|
||||
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
|
||||
fn libc_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -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>> {
|
||||
let this = self.eval_context_ref();
|
||||
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());
|
||||
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),
|
||||
// we specifically look up the static in libstd that we know is placed
|
||||
// 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 =
|
||||
this.eval_windows("thread_local_key", "p_thread_callback")?.to_pointer(this)?;
|
||||
let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?;
|
||||
|
@ -11,7 +11,6 @@ use std::time::SystemTime;
|
||||
use log::trace;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::ty::{self, layout::LayoutOf};
|
||||
use rustc_target::abi::{Align, Size};
|
||||
|
||||
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
|
||||
// `statxbuf_op` by using the `libc::statx` struct type.
|
||||
let statxbuf = {
|
||||
// FIXME: This long path is required because `libc::statx` is an struct and also a
|
||||
// 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)?;
|
||||
let statx_layout = this.libc_ty_layout("statx")?;
|
||||
MPlaceTy::from_aligned_ptr(statxbuf_ptr, statx_layout)
|
||||
};
|
||||
|
||||
|
@ -1,9 +1,5 @@
|
||||
#![feature(lang_items, start)]
|
||||
#![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:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user