Skip to content

Commit 144b485

Browse files
committed
Auto merge of rust-lang#2696 - RalfJung:no-std-windows, r=RalfJung
make no_std work on Windows Also fixes rust-lang/miri#1123 by cherry-picking a patch by `@DrMeepster.`
2 parents b3e4402 + 3158a8d commit 144b485

File tree

6 files changed

+71
-43
lines changed

6 files changed

+71
-43
lines changed

src/tools/miri/ci.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ function run_tests_minimal {
8888
./miri test -- "$@"
8989

9090
# Ensure that a small smoke test of cargo-miri works.
91-
# Note: This doesn't work on windows because of TLS.
9291
cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml
9392

9493
endgroup

src/tools/miri/src/eval.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::thread;
99
use log::info;
1010

1111
use rustc_data_structures::fx::FxHashSet;
12+
use rustc_hir::def::Namespace;
1213
use rustc_hir::def_id::DefId;
1314
use rustc_middle::ty::{
1415
self,
@@ -195,7 +196,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
195196
MiriMachine::late_init(&mut ecx, config)?;
196197

197198
// Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
198-
let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"]);
199+
let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"], Namespace::ValueNS);
199200
if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) {
200201
tcx.sess.fatal(
201202
"the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \

src/tools/miri/src/helpers.rs

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ pub mod convert;
22

33
use std::cmp;
44
use std::iter;
5-
use std::mem;
65
use std::num::NonZeroUsize;
76
use std::time::Duration;
87

98
use log::trace;
109

10+
use rustc_hir::def::{DefKind, Namespace};
1111
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
1212
use rustc_middle::mir;
1313
use rustc_middle::ty::{
@@ -74,48 +74,79 @@ const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
7474
};
7575

7676
/// Gets an instance for a path.
77-
fn try_resolve_did<'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option<DefId> {
78-
tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then(
79-
|krate| {
80-
let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX };
81-
let mut items = tcx.module_children(krate);
82-
let mut path_it = path.iter().skip(1).peekable();
83-
84-
while let Some(segment) = path_it.next() {
85-
for item in mem::take(&mut items).iter() {
86-
if item.ident.name.as_str() == *segment {
87-
if path_it.peek().is_none() {
88-
return Some(item.res.def_id());
89-
}
77+
///
78+
/// A `None` namespace indicates we are looking for a module.
79+
fn try_resolve_did<'tcx>(
80+
tcx: TyCtxt<'tcx>,
81+
path: &[&str],
82+
namespace: Option<Namespace>,
83+
) -> Option<DefId> {
84+
/// Yield all children of the given item, that have the given name.
85+
fn find_children<'tcx: 'a, 'a>(
86+
tcx: TyCtxt<'tcx>,
87+
item: DefId,
88+
name: &'a str,
89+
) -> impl Iterator<Item = DefId> + 'a {
90+
tcx.module_children(item)
91+
.iter()
92+
.filter(move |item| item.ident.name.as_str() == name)
93+
.map(move |item| item.res.def_id())
94+
}
9095

91-
items = tcx.module_children(item.res.def_id());
92-
break;
93-
}
94-
}
95-
}
96-
None
97-
},
98-
)
96+
// Take apart the path: leading crate, a sequence of modules, and potentially a final item.
97+
let (&crate_name, path) = path.split_first().expect("paths must have at least one segment");
98+
let (modules, item) = if let Some(namespace) = namespace {
99+
let (&item_name, modules) =
100+
path.split_last().expect("non-module paths must have at least 2 segments");
101+
(modules, Some((item_name, namespace)))
102+
} else {
103+
(path, None)
104+
};
105+
106+
// First find the crate.
107+
let krate =
108+
tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == crate_name)?;
109+
let mut cur_item = DefId { krate: *krate, index: CRATE_DEF_INDEX };
110+
// Then go over the modules.
111+
for &segment in modules {
112+
cur_item = find_children(tcx, cur_item, segment)
113+
.find(|item| tcx.def_kind(item) == DefKind::Mod)?;
114+
}
115+
// Finally, look up the desired item in this module, if any.
116+
match item {
117+
Some((item_name, namespace)) =>
118+
Some(
119+
find_children(tcx, cur_item, item_name)
120+
.find(|item| tcx.def_kind(item).ns() == Some(namespace))?,
121+
),
122+
None => Some(cur_item),
123+
}
99124
}
100125

101126
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
127+
/// Checks if the given crate/module exists.
128+
fn have_module(&self, path: &[&str]) -> bool {
129+
try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some()
130+
}
131+
102132
/// Gets an instance for a path; fails gracefully if the path does not exist.
103-
fn try_resolve_path(&self, path: &[&str]) -> Option<ty::Instance<'tcx>> {
104-
let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path)?;
105-
Some(ty::Instance::mono(self.eval_context_ref().tcx.tcx, did))
133+
fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option<ty::Instance<'tcx>> {
134+
let tcx = self.eval_context_ref().tcx.tcx;
135+
let did = try_resolve_did(tcx, path, Some(namespace))?;
136+
Some(ty::Instance::mono(tcx, did))
106137
}
107138

108139
/// Gets an instance for a path.
109-
fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> {
110-
self.try_resolve_path(path)
140+
fn resolve_path(&self, path: &[&str], namespace: Namespace) -> ty::Instance<'tcx> {
141+
self.try_resolve_path(path, namespace)
111142
.unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
112143
}
113144

114145
/// Evaluates the scalar at the specified path. Returns Some(val)
115146
/// if the path could be resolved, and None otherwise
116147
fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar<Provenance>> {
117148
let this = self.eval_context_ref();
118-
let instance = this.resolve_path(path);
149+
let instance = this.resolve_path(path, Namespace::ValueNS);
119150
let cid = GlobalId { instance, promoted: None };
120151
// We don't give a span -- this isn't actually used directly by the program anyway.
121152
let const_val = this.eval_global(cid, None)?;
@@ -147,15 +178,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
147178
/// Helper function to get the `TyAndLayout` of a `libc` type
148179
fn libc_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
149180
let this = self.eval_context_ref();
150-
let ty = this.resolve_path(&["libc", name]).ty(*this.tcx, ty::ParamEnv::reveal_all());
181+
let ty = this
182+
.resolve_path(&["libc", name], Namespace::TypeNS)
183+
.ty(*this.tcx, ty::ParamEnv::reveal_all());
151184
this.layout_of(ty)
152185
}
153186

154187
/// Helper function to get the `TyAndLayout` of a `windows` type
155188
fn windows_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
156189
let this = self.eval_context_ref();
157190
let ty = this
158-
.resolve_path(&["std", "sys", "windows", "c", name])
191+
.resolve_path(&["std", "sys", "windows", "c", name], Namespace::TypeNS)
159192
.ty(*this.tcx, ty::ParamEnv::reveal_all());
160193
this.layout_of(ty)
161194
}

src/tools/miri/src/shims/tls.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
261261
// (that would be basically https://github.com/rust-lang/miri/issues/450),
262262
// we specifically look up the static in libstd that we know is placed
263263
// in that section.
264+
if !this.have_module(&["std"]) {
265+
// Looks like we are running in a `no_std` crate.
266+
// That also means no TLS dtors callback to call.
267+
return Ok(());
268+
}
264269
let thread_callback =
265270
this.eval_windows("thread_local_key", "p_thread_callback")?.to_pointer(this)?;
266271
let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?;

src/tools/miri/src/shims/unix/fs.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use std::time::SystemTime;
1111
use log::trace;
1212

1313
use rustc_data_structures::fx::FxHashMap;
14-
use rustc_middle::ty::{self, layout::LayoutOf};
1514
use rustc_target::abi::{Align, Size};
1615

1716
use crate::shims::os_str::bytes_to_os_str;
@@ -1006,12 +1005,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10061005
// as `isize`s instead of having the proper types. Thus, we have to recover the layout of
10071006
// `statxbuf_op` by using the `libc::statx` struct type.
10081007
let statxbuf = {
1009-
// FIXME: This long path is required because `libc::statx` is an struct and also a
1010-
// function and `resolve_path` is returning the latter.
1011-
let statx_ty = this
1012-
.resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"])
1013-
.ty(*this.tcx, ty::ParamEnv::reveal_all());
1014-
let statx_layout = this.layout_of(statx_ty)?;
1008+
let statx_layout = this.libc_ty_layout("statx")?;
10151009
MPlaceTy::from_aligned_ptr(statxbuf_ptr, statx_layout)
10161010
};
10171011

src/tools/miri/tests/pass/no_std.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
#![feature(lang_items, start)]
22
#![no_std]
3-
// windows tls dtors go through libstd right now, thus this test
4-
// cannot pass. When windows tls dtors go through the special magic
5-
// windows linker section, we can run this test on windows again.
6-
//@ignore-target-windows: no-std not supported on Windows
73

84
// Plumbing to let us use `writeln!` to host stdout:
95

0 commit comments

Comments
 (0)